// TODO: second argument should be options (initial zoom and center, icon root path)
// TODO: could extract the golf course specifics from a plotter API
// -- IconMapper to choose icon for entry, InfoBuilder to create the contents for the info window
function GCPlotter( containerId, iconRootPath ) {
	this.GMap = null;
	this.GeoCoder = null;
	this.containerId = containerId;
	this.iconRootPath = iconRootPath;
	this.items = {};
	this.boundaries = null;
	this.markerIconCache = {};
}

GCPlotter.prototype = {

	isAvailable : function() {
		return typeof GMap2 == 'function' && GBrowserIsCompatible() && document.getElementById( this.containerId );
	},

	addMarkers : function( courses ) {
		if ( !courses ) {
			document.getElementById( this.containerId ).innerHTML = "<p>Failed to load courses.</p>";
			return;
		}

		var loaded = this._initMap();
		if ( !loaded ) {
			document.getElementById( this.containerId ).innerHTML = "<p>Failed to load map.</p>";
			return;
		}
		
		for ( var i = 0; i < courses.length; i++ ) {
			this.addMarker( courses[i], ( i + 1 ) == courses.length );
		}
		
		// cannot zoom since points are placed in a callback and thus not yet registered
		//this.zoomToFit();
	},

	// TODO: if I loaded prototype, I could make the callback a class method
	addMarker : function( course, last ) {
		var self = this;
		var item = { data: course, marker: null };	
		this.items[course.getId()] = item;
		this.GeoCoder.getLatLng(
			this.buildAddressString( course.getAddress() ),
			function( geopoint ) {
				if ( !geopoint ) {
					return;
				}
				
				var marker = new GMarker( geopoint, { icon: self.getMarkerIcon( course.getType() ) } );
				item.marker = marker;
				self.GMap.addOverlay( marker );
				GEvent.addListener( marker, "click", function() {
					self.displayInfoBalloon( course.getId() );
				} );
				
				self._updateBoundaries( geopoint.lat(), geopoint.lng() );
				// not the most optimal, but at least it will always end up zoomed correctly
				self.zoomToFit();
			}
	    );
	},

	zoomToFit : function() {
		if ( this.boundaries == null ) {
			return;
		}
		
		var sw = new GLatLng( this.boundaries.minLat, this.boundaries.minLng );
		var ne = new GLatLng( this.boundaries.maxLat, this.boundaries.maxLng );
		var bounds = new GLatLngBounds( sw, ne )
		var zoom = this.GMap.getBoundsZoomLevel( bounds );
		this.GMap.setZoom( zoom > 13 ? 13 : zoom );
		this.GMap.setCenter( new GLatLng( this.boundaries.centerLat, this.boundaries.centerLng ) );
	},

	displayInfoBalloon : function( courseId ) {
		var course = this.items[courseId].data;
		var info = document.createElement( 'div' );

		var title = document.createElement( 'strong' );
		title.appendChild( document.createTextNode( course.getName() ) );

		var endline = document.createElement( 'br' );

		var location = document.createElement( 'small' );
		location.appendChild( document.createTextNode( course.getAddress().getCity() + ", " + course.getAddress().getState() ) );

		info.appendChild( title );
		info.appendChild( endline );
		info.appendChild( location );
		this.items[courseId].marker.openInfoWindow( info );
	},

	getMarkerIcon : function( courseType ) {
		if ( this.markerIconCache[courseType] ) {
			return this.markerIconCache[courseType];
		}
		
		var icon = new GIcon();  
		icon.image = this.iconRootPath + courseType.toLowerCase() + ".png";
		icon.shadow = this.iconRootPath + "shadow.png";
		icon.iconSize = new GSize( 24, 24 );
		icon.shadowSize = new GSize( 32, 24 );
		icon.iconAnchor = new GPoint( 12, 24 );
		icon.infoWindowAnchor = new GPoint( 3, 3 );
		this.markerIconCache[courseType] = icon;
		
		return icon;
	},

	buildAddressString : function( address ) {
		// TODO: perhaps use join(" ")?
		return address.getStreet() + ", " + address.getCity() + ", " + address.getState() + " " + address.getPostalCode();
	},

	_updateBoundaries : function( lat, lng ) {
		if ( this.boundaries == null ) {
			this.boundaries = { minLat : lat, maxLat : lat, minLng : lng, maxLng : lng };
		}
		else {
			if ( lat < this.boundaries.minLat ) {
				this.boundaries.minLat = lat;
			}
			else if ( lat > this.boundaries.maxLat ) {
				this.boundaries.maxLat = lat;
			}
			
			if ( lng < this.boundaries.minLng ) {
				this.boundaries.minLng = lng;
			}
			else if ( lng > this.boundaries.maxLng ) {
				this.boundaries.maxLng = lng;
			}
		}
		
		this.boundaries.centerLat = this.boundaries.minLat + ( ( this.boundaries.maxLat - this.boundaries.minLat ) / 2 );
		this.boundaries.centerLng = this.boundaries.minLng + ( ( this.boundaries.maxLng - this.boundaries.minLng ) / 2 );
	},

	_initMap : function() {
		try {
			this.GMap = new GMap2( document.getElementById( this.containerId ) );
			this.GMap.addControl( new GSmallMapControl() );
			this.GMap.addControl( new GMapTypeControl() );
			this.GeoCoder = new GClientGeocoder();
			this.GMap.setCenter( new GLatLng( 39.8128, -98.5580 ), 1);
			//this.GMap.setCenter( new GLatLng( 37.4419, -122.1419 ), 1 );
			window.onunload = GUnload;
		} catch (e) {
			return false;
		}
		
		return true;
	}

};
